@file:Suppress("unused", "NOTHING_TO_INLINE")

package com.xh.baselibrary.ex

import java.io.*
import java.nio.charset.Charset


/**
 * 循环从流中以字节的方式读取数据传递给[handler]处理，直到读取完成。
 *
 * @param bufferSize 每次读取数据的buffer大小
 * @param handler    用于处理读取到的数据
 *
 * @see InputStream.forEachIf
 */
fun <T: InputStream> T.forEach(bufferSize: Int = DEFAULT_BUFFER_SIZE, handler: (buffer: ByteArray, size: Int) -> Unit): T {
    return this.forEachIf(bufferSize) { buffer, size ->
        handler(buffer, size)
        true
    }
}

/**
 * 循环从流中以字节的方式读取数据传递给[handler]处理，直到读取完成或[handler]返回false。
 *
 * @param bufferSize 每次读取数据的buffer大小
 * @param handler    用于处理读取到的数据
 *
 * @see InputStream.forEach
 */
fun <T: InputStream> T.forEachIf(bufferSize: Int = DEFAULT_BUFFER_SIZE, handler: (buffer: ByteArray, size: Int) -> Boolean): T {
    val buffer = ByteArray(bufferSize)
    var numRead: Int

    while (true) {
        numRead = this.read(buffer)
        if (numRead == -1 || !handler(buffer, numRead)) {
            break
        }
    }

    return this
}

/**
 * 循环从流中以字符的方式读取数据传递给[handler]处理，直到读取完成。
 *
 * @param bufferSize 每次读取数据的buffer大小
 * @param handler    用于处理读取到的数据
 *
 * @see Reader.forEachIf
 */
fun <T: Reader> T.forEach(bufferSize: Int = DEFAULT_BUFFER_SIZE, handler: (buffer: CharArray, size: Int) -> Unit): T {
    return this.forEachIf(bufferSize) { buffer, size ->
        handler(buffer, size)
        true
    }
}

/**
 * 循环从流中以字符的方式读取数据传递给[handler]处理，直到读取完成或[handler]返回false。
 *
 * @param bufferSize 每次读取数据的buffer大小
 * @param handler    用于处理读取到的数据
 *
 * @see Reader.forEachIf
 */
fun <T: Reader> T.forEachIf(bufferSize: Int = DEFAULT_BUFFER_SIZE, handler: (buffer: CharArray, size: Int) -> Boolean): T {
    val buffer = CharArray(bufferSize)
    var numRead: Int
    while (true) {
        numRead = this.read(buffer)
        if (numRead == -1 || !handler(buffer, numRead)) {
            break
        }
    }

    return this
}


/**
 * 一行一行处理指定文件的内容。
 *
 * @param handler  每行的处理器
 *
 * @see Reader.forEachLinesIf
 * @see Reader.forEachLine
 */
fun <T: Reader> T.forEachLines(handler: (line: String) -> Unit): T {
    this.forEachLine(handler)
    return this
}

/**
 * 一行一行处理指定文件的内容。
 *
 * @param handler 每行的处理器，返回true表示继续处理下一行，否则表示处理结束
 *
 * @see Reader.forEachLines
 * @see Reader.forEachLine
 */
fun <T: Reader> T.forEachLinesIf(handler: (line: String) -> Boolean): T {
    val reader = this.buffered()
    var line: String?

    while (true) {
        line = reader.readLine()
        if (line == null || !handler(line)) {
            break
        }
    }

    return this
}

/**
 * 一行一行处理指定文件的内容。
 *
 * @param handler   每行的处理器
 * @param exception 异常回调
 *
 * @see File.forEachLine
 * @see File.forEachLinesIf
 */
fun File.forEachLines(charset: Charset = Charsets.UTF_8, exception: (Throwable) -> Unit = {}, handler: (String) -> Unit): File {
    runCatching { this.forEachLine(charset, handler) }.exceptionOrNull()?.let { exception(it) }
    return this
}

/**
 * 一行一行处理指定文件的内容。
 *
 * @param handler   每行的处理器，返回true表示继续处理下一行，否则表示处理结束
 * @param exception 异常回调
 *
 * @see File.forEachLine
 * @see File.forEachLines
 */
fun File.forEachLinesIf(charset: Charset = Charsets.UTF_8, exception: (Throwable) -> Unit = {}, handler: (String) -> Boolean): File {
    runCatching {
        this.reader(charset).buffered().use {
            var line: String?

            while (true) {
                line = it.readLine()
                if (line == null || !handler(line)) {
                    break
                }
            }
        }
    }.exceptionOrNull()?.let { exception(it) }

    return this
}

/**
 * 查找行
 *
 * @param exception 异常回调
 * @param handler   每行的处理器，如果返回值不是null，则表示查找结束，并返回handler返回的字符串。
 */
fun File.searchLine(charset: Charset = Charsets.UTF_8, exception: (Throwable) -> Unit = {}, handler: (String) -> String?): String? {
    var line: String? = null

    this.forEachLinesIf(charset, exception) { l ->
        line = handler(l)
        return@forEachLinesIf line == null
    }

    return line
}

/**
 * 按字符处理指定文件的内容。
 *
 * @param handler    处理器，每读取一次回调一次，如果返回true表示继续读取并处理，否则表示处理结束
 * @param bufferSize 每次读取的buffer大小
 * @param exception  异常回调
 */
fun File.chars(bufferSize: Int = DEFAULT_BUFFER_SIZE, exception: (Throwable) -> Unit = {}, handler: (buffer: CharArray, size: Int) -> Boolean) {
    var reader: InputStreamReader? = null
    try {
        reader = this.reader().forEachIf(bufferSize, handler)
    } catch (e: Exception) {
        exception(e)
    } finally {
        reader.closeQuietly(exception)
    }
}

/**
 * 按字节处理指定文件的内容。
 *
 * @param handler    处理器，每读取一次回调一次，如果返回true表示继续读取并处理，否则表示处理结束
 * @param bufferSize 每次读取的buffer大小
 * @param exception  异常回调
 */
fun File.bytes(bufferSize: Int = DEFAULT_BUFFER_SIZE, exception: (Throwable) -> Unit = {}, handler: (buffer: ByteArray, size: Int) -> Boolean) {
    var fis: FileInputStream? = null
    try {
        fis = this.inputStream().forEachIf(bufferSize, handler)
    } catch (e: Exception) {
        exception(e)
    } finally {
        fis.closeQuietly(exception)
    }
}

inline fun <reified T: Closeable> T?.closeQuietly(throws: (Throwable) -> Unit = {}) {
    runCatching { this?.close() }.exceptionOrNull()?.let { throws(it) }
}

